📚 MzalendoPay Proxy API Documentation
Complete Integration Guide for Merchants
Overview
Welcome to the MzalendoPay Proxy API! This service allows you to accept mobile money payments (M-Pesa, Tigo Pesa, Airtel Money) on your website through a simple integration. Our proxy handles all the complex payment processing so you can focus on your business.

What This API Does
✅ Creates payment orders and sends USSD prompts to customers

✅ Checks payment status in real-time

✅ Receives webhook notifications when payments succeed

✅ Automatically handles all MzalendoPay gateway communication

Base URL
text
https://kupursa.store/api/mzalendo_proxy.php
Supported Methods
POST - Create payments

GET - Check payment status

Content-Type
text
application/json
🔐 Authentication
All API requests require authentication using your Platform API Key. You receive this key when you register as a merchant on our platform.

Headers
Header	Required	Description
X-API-KEY	Yes	Your unique platform API key
Example Headers
http
X-API-KEY: mzk_8f3e2a1b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f
Content-Type: application/json
📡 API Endpoints
1. Create Payment
Initiates a payment and sends a USSD prompt to the customer's phone.

Endpoint: POST ?action=create_payment

Request Body
Field	Type	Required	Description
customer_name	string	Yes	Customer's full name
customer_email	string	Yes	Customer's email address
customer_phone	string	Yes	Phone number (format: 0712345678)
amount	decimal	Yes	Amount in TZS (minimum 500)
description	string	Yes	Payment reason (e.g., "Premium Subscription")
Example Request
bash
curl -X POST https://kupursa.store/api/mzalendo_proxy.php?action=create_payment \
  -H "X-API-KEY: your_platform_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_name": "John Doe",
    "customer_email": "john@example.com",
    "customer_phone": "0712345678",
    "amount": 5000,
    "description": "Premium Content Access"
  }'
Successful Response
json
{
    "success": true,
    "order_id": "ORD-1703123456-7890",
    "payment_id": 12345,
    "message": "USSD inatumwa kwenye simu yako..."
}
Error Responses
json
{
    "success": false,
    "message": "Invalid API key"
}
json
{
    "success": false,
    "message": "Missing required field: customer_phone"
}
json
{
    "success": false,
    "message": "Invalid merchant credentials"
}
2. Check Payment Status
Retrieves the current status of a payment order.

Endpoint: GET ?action=check_status

Query Parameters
Parameter	Required	Description
order_id	Yes	The order_id returned from create_payment
Example Request
bash
curl -X GET "https://kupursa.store/api/mzalendo_proxy.php?action=check_status&order_id=ORD-1703123456-7890" \
  -H "X-API-KEY: your_platform_api_key"
Pending Response
json
{
    "success": true,
    "order_id": "ORD-1703123456-7890",
    "status": "PENDING",
    "amount": "5000.00",
    "customer_name": "John Doe"
}
Successful Payment Response
json
{
    "success": true,
    "order_id": "ORD-1703123456-7890",
    "status": "SUCCESS",
    "transid": "TXN_MPESA_001",
    "channel": "MPESA",
    "amount": "5000.00",
    "customer_name": "John Doe"
}
Failed Payment Response
json
{
    "success": true,
    "order_id": "ORD-1703123456-7890",
    "status": "FAILED",
    "amount": "5000.00",
    "customer_name": "John Doe"
}
3. Webhook Notifications
When a payment is successfully completed, we will send a POST request to your configured webhook URL. Set your webhook URL in your merchant dashboard.

Webhook Headers
Header	Description
X-MzalendoPay-Event	Event type (e.g., payment.success)
X-MzalendoPay-Signature	HMAC signature for verification
Webhook Payload
json
{
    "event": "payment.success",
    "order_id": "ORD-1703123456-7890",
    "status": "SUCCESS",
    "transid": "TXN_MPESA_001",
    "channel": "MPESA",
    "data": {
        "payment_status": "SUCCESS",
        "transaction_id": "TXN_MPESA_001",
        "amount": 5000,
        "currency": "TZS",
        "buyer_phone": "255712345678",
        "buyer_name": "John Doe"
    },
    "timestamp": "2024-01-15T10:30:00+03:00"
}
Your Webhook Should:
Return a 200 OK response within 10 seconds

Respond with {"success": true} to acknowledge receipt

Process the payment confirmation (grant access, update records)

💻 Integration Examples
JavaScript (Browser)
javascript
class MzalendoPayClient {
    constructor(apiKey) {
        this.apiKey = apiKey;
        this.apiBase = 'https://kupursa.store/api/mzalendo_proxy.php';
    }
    
    async createPayment(paymentData) {
        const response = await fetch(`${this.apiBase}?action=create_payment`, {
            method: 'POST',
            headers: {
                'X-API-KEY': this.apiKey,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(paymentData)
        });
        
        return await response.json();
    }
    
    async checkStatus(orderId) {
        const response = await fetch(`${this.apiBase}?action=check_status&order_id=${orderId}`, {
            headers: {
                'X-API-KEY': this.apiKey
            }
        });
        
        return await response.json();
    }
    
    async waitForPayment(orderId, interval = 5000, maxAttempts = 24) {
        for (let i = 0; i < maxAttempts; i++) {
            const result = await this.checkStatus(orderId);
            
            if (result.status === 'SUCCESS') {
                return { success: true, payment: result };
            } else if (result.status === 'FAILED') {
                return { success: false, error: 'Payment failed' };
            }
            
            await new Promise(resolve => setTimeout(resolve, interval));
        }
        
        return { success: false, error: 'Timeout' };
    }
}

// Usage Example
const mz = new MzalendoPayClient('your_platform_api_key');

// Create payment
const payment = await mz.createPayment({
    customer_name: 'John Doe',
    customer_email: 'john@example.com',
    customer_phone: '0712345678',
    amount: 5000,
    description: 'Premium Access'
});

if (payment.success) {
    console.log('Order ID:', payment.order_id);
    
    // Wait for payment completion
    const result = await mz.waitForPayment(payment.order_id);
    
    if (result.success) {
        console.log('Payment successful!', result.payment);
        // Grant access to content
        window.location.href = '/success-page';
    } else {
        alert('Payment failed. Please try again.');
    }
}
PHP (Backend)
php
<?php
class MzalendoPay {
    private $apiKey;
    private $apiBase = 'https://kupursa.store/api/mzalendo_proxy.php';
    
    public function __construct($apiKey) {
        $this->apiKey = $apiKey;
    }
    
    public function createPayment($customerName, $customerEmail, $customerPhone, $amount, $description) {
        $payload = [
            'customer_name' => $customerName,
            'customer_email' => $customerEmail,
            'customer_phone' => $customerPhone,
            'amount' => $amount,
            'description' => $description
        ];
        
        $ch = curl_init($this->apiBase . '?action=create_payment');
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_HTTPHEADER => [
                'X-API-KEY: ' . $this->apiKey,
                'Content-Type: application/json'
            ]
        ]);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        return json_decode($response, true);
    }
    
    public function checkStatus($orderId) {
        $ch = curl_init($this->apiBase . '?action=check_status&order_id=' . urlencode($orderId));
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => ['X-API-KEY: ' . $this->apiKey]
        ]);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        return json_decode($response, true);
    }
    
    public function waitForPayment($orderId, $interval = 5, $maxAttempts = 24) {
        for ($i = 0; $i < $maxAttempts; $i++) {
            $result = $this->checkStatus($orderId);
            
            if ($result['status'] === 'SUCCESS') {
                return ['success' => true, 'payment' => $result];
            } elseif ($result['status'] === 'FAILED') {
                return ['success' => false, 'error' => 'Payment failed'];
            }
            
            sleep($interval);
        }
        
        return ['success' => false, 'error' => 'Timeout'];
    }
}

// Usage Example
$mz = new MzalendoPay('your_platform_api_key');

// Create payment
$payment = $mz->createPayment(
    'John Doe',
    'john@example.com',
    '0712345678',
    5000,
    'Premium Access'
);

if ($payment['success']) {
    $orderId = $payment['order_id'];
    echo "Payment created: {$orderId}\n";
    
    // Wait for completion
    $result = $mz->waitForPayment($orderId);
    
    if ($result['success']) {
        echo "Payment successful! Transaction: {$result['payment']['transid']}\n";
        // Grant access to customer
    } else {
        echo "Payment failed or timed out\n";
    }
}
?>
Python
python
import requests
import time

class MzalendoPay:
    def __init__(self, api_key):
        self.api_key = api_key
        self.api_base = 'https://kupursa.store/api/mzalendo_proxy.php'
    
    def create_payment(self, customer_name, customer_email, customer_phone, amount, description):
        payload = {
            'customer_name': customer_name,
            'customer_email': customer_email,
            'customer_phone': customer_phone,
            'amount': amount,
            'description': description
        }
        
        headers = {
            'X-API-KEY': self.api_key,
            'Content-Type': 'application/json'
        }
        
        response = requests.post(
            f'{self.api_base}?action=create_payment',
            json=payload,
            headers=headers
        )
        
        return response.json()
    
    def check_status(self, order_id):
        headers = {'X-API-KEY': self.api_key}
        
        response = requests.get(
            f'{self.api_base}?action=check_status&order_id={order_id}',
            headers=headers
        )
        
        return response.json()
    
    def wait_for_payment(self, order_id, interval=5, max_attempts=24):
        for _ in range(max_attempts):
            result = self.check_status(order_id)
            
            if result['status'] == 'SUCCESS':
                return {'success': True, 'payment': result}
            elif result['status'] == 'FAILED':
                return {'success': False, 'error': 'Payment failed'}
            
            time.sleep(interval)
        
        return {'success': False, 'error': 'Timeout'}

# Usage Example
mz = MzalendoPay('your_platform_api_key')

# Create payment
payment = mz.create_payment(
    customer_name='John Doe',
    customer_email='john@example.com',
    customer_phone='0712345678',
    amount=5000,
    description='Premium Access'
)

if payment['success']:
    print(f"Order ID: {payment['order_id']}")
    
    # Wait for completion
    result = mz.wait_for_payment(payment['order_id'])
    
    if result['success']:
        print(f"Payment successful! Transaction: {result['payment']['transid']}")
        # Grant access to customer
🌐 HTML/PHP Integration Example
Here's a complete example you can use on your website:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Payment Integration - MzalendoPay</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }
        .payment-card {
            background: white;
            border-radius: 20px;
            padding: 30px;
            max-width: 400px;
            width: 100%;
            box-shadow: 0 20px 40px rgba(0,0,0,0.1);
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #333;
        }
        input, button {
            width: 100%;
            padding: 12px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 16px;
        }
        button {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            border: none;
            font-weight: 600;
            cursor: pointer;
            transition: transform 0.2s;
        }
        button:hover {
            transform: translateY(-2px);
        }
        .status {
            margin-top: 20px;
            padding: 12px;
            border-radius: 10px;
            display: none;
        }
        .status.success {
            background: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }
        .status.error {
            background: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }
        .status.pending {
            background: #fff3cd;
            color: #856404;
            border: 1px solid #ffeaa7;
        }
        .spinner {
            display: inline-block;
            width: 14px;
            height: 14px;
            border: 2px solid white;
            border-top-color: transparent;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-left: 8px;
        }
        @keyframes spin {
            to { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
    <div class="payment-card">
        <h2 style="text-align:center; margin-bottom:20px;">💳 Make Payment</h2>
        
        <div class="form-group">
            <label>Full Name</label>
            <input type="text" id="name" placeholder="John Doe">
        </div>
        
        <div class="form-group">
            <label>Email</label>
            <input type="email" id="email" placeholder="john@example.com">
        </div>
        
        <div class="form-group">
            <label>Phone Number</label>
            <input type="tel" id="phone" placeholder="0712345678">
        </div>
        
        <div class="form-group">
            <label>Amount (TZS)</label>
            <input type="number" id="amount" placeholder="5000" min="500" value="5000">
        </div>
        
        <button id="payBtn">Pay Now</button>
        
        <div id="status" class="status"></div>
    </div>

    <script>
        // Your Platform API Key from merchant dashboard
        const API_KEY = 'YOUR_PLATFORM_API_KEY'; // ← Replace with your actual API key
        
        class MzalendoPayClient {
            constructor(apiKey) {
                this.apiKey = apiKey;
                this.apiBase = 'https://kupursa.store/api/mzalendo_proxy.php';
            }
            
            async createPayment(data) {
                const response = await fetch(`${this.apiBase}?action=create_payment`, {
                    method: 'POST',
                    headers: {
                        'X-API-KEY': this.apiKey,
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(data)
                });
                return await response.json();
            }
            
            async checkStatus(orderId) {
                const response = await fetch(`${this.apiBase}?action=check_status&order_id=${orderId}`, {
                    headers: { 'X-API-KEY': this.apiKey }
                });
                return await response.json();
            }
            
            async waitForPayment(orderId, interval = 5000, maxAttempts = 24) {
                for (let i = 0; i < maxAttempts; i++) {
                    const result = await this.checkStatus(orderId);
                    
                    if (result.status === 'SUCCESS') {
                        return { success: true, payment: result };
                    } else if (result.status === 'FAILED') {
                        return { success: false, error: 'Payment failed' };
                    }
                    
                    await new Promise(resolve => setTimeout(resolve, interval));
                }
                return { success: false, error: 'Timeout' };
            }
        }
        
        const mzClient = new MzalendoPayClient(API_KEY);
        
        document.getElementById('payBtn').addEventListener('click', async () => {
            const name = document.getElementById('name').value;
            const email = document.getElementById('email').value;
            const phone = document.getElementById('phone').value;
            const amount = document.getElementById('amount').value;
            const statusDiv = document.getElementById('status');
            const payBtn = document.getElementById('payBtn');
            
            // Validate inputs
            if (!name || !email || !phone || !amount) {
                statusDiv.className = 'status error';
                statusDiv.style.display = 'block';
                statusDiv.innerHTML = '❌ Please fill in all fields';
                return;
            }
            
            if (!/^0[67][0-9]{8}$/.test(phone)) {
                statusDiv.className = 'status error';
                statusDiv.style.display = 'block';
                statusDiv.innerHTML = '❌ Phone number must start with 07 or 06 (e.g., 0712345678)';
                return;
            }
            
            if (amount < 500) {
                statusDiv.className = 'status error';
                statusDiv.style.display = 'block';
                statusDiv.innerHTML = '❌ Minimum amount is TZS 500';
                return;
            }
            
            // Disable button and show loading
            payBtn.disabled = true;
            payBtn.innerHTML = 'Processing... <span class="spinner"></span>';
            
            statusDiv.className = 'status pending';
            statusDiv.style.display = 'block';
            statusDiv.innerHTML = '⏳ Creating payment order...';
            
            try {
                // Create payment
                const payment = await mzClient.createPayment({
                    customer_name: name,
                    customer_email: email,
                    customer_phone: phone,
                    amount: amount,
                    description: 'Website Purchase'
                });
                
                if (!payment.success) {
                    throw new Error(payment.message || 'Payment creation failed');
                }
                
                statusDiv.innerHTML = `✅ Order created: ${payment.order_id}<br>📱 USSD inatumwa kwenye simu yako...<br>Please check your phone and enter PIN`;
                
                // Wait for payment completion
                statusDiv.innerHTML += '<br>⏳ Waiting for payment confirmation...';
                
                const result = await mzClient.waitForPayment(payment.order_id);
                
                if (result.success) {
                    statusDiv.className = 'status success';
                    statusDiv.innerHTML = `✅ PAYMENT SUCCESSFUL!<br>Transaction ID: ${result.payment.transid}<br>Amount: TZS ${result.payment.amount}<br>Thank you for your purchase!`;
                    // Grant access to content here
                    setTimeout(() => {
                        window.location.href = '/success-page';
                    }, 3000);
                } else {
                    throw new Error(result.error || 'Payment failed');
                }
                
            } catch (error) {
                statusDiv.className = 'status error';
                statusDiv.innerHTML = `❌ Error: ${error.message}<br>Please try again or contact support.`;
            } finally {
                payBtn.disabled = false;
                payBtn.innerHTML = 'Pay Now';
            }
        });
    </script>
</body>
</html>
📋 Webhook Handler Example
Create a webhook endpoint on your server to receive payment confirmations:

php
<?php
// webhook_handler.php - Place on your server
// Set this URL in your merchant dashboard

$input = json_decode(file_get_contents('php://input'), true);

// Verify the webhook signature (optional but recommended)
// $signature = $_SERVER['HTTP_X_MZALENDOPAY_SIGNATURE'] ?? '';
// if (!verifySignature($input, $signature)) {
//     http_response_code(401);
//     exit;
// }

if ($input['event'] === 'payment.success') {
    $orderId = $input['order_id'];
    $transactionId = $input['transid'];
    $amount = $input['data']['amount'];
    
    // Update your database
    $stmt = $pdo->prepare("UPDATE orders SET status = 'paid', transaction_id = ? WHERE order_id = ?");
    $stmt->execute([$transactionId, $orderId]);
    
    // Grant access to customer
    // Send confirmation email
    // Update user account
    
    error_log("Payment successful: Order $orderId, Transaction $transactionId");
}

// Always return 200 OK
http_response_code(200);
echo json_encode(['success' => true]);
?>
❌ Error Codes
Error Message	Description	Solution
Invalid API key	Your Platform API Key is incorrect	Check your API key in merchant dashboard
Missing required field	Required field is empty	Ensure all required fields are provided
Invalid merchant credentials	Your merchant account is not active	Contact support to activate your account
Namba lazima ianze na 07 au 06	Invalid phone number format	Use format: 0712345678 or 255712345678
Gateway connection error	Unable to reach payment gateway	Check your internet connection, try again
Rate limit exceeded	Too many requests	Wait a minute before trying again
✅ Best Practices
1. Phone Number Format
Always collect phone numbers in local format:

✅ Good: 0712345678 or 255712345678

❌ Bad: 712345678 or +255712345678

2. Polling Interval
When checking payment status:

Poll every 5-10 seconds

Maximum 24 attempts (2 minutes)

Show progress to customer

3. Webhook Reliability
Return 200 OK within 10 seconds

Make your webhook handler idempotent

Log all webhook events for debugging

4. Security
Never expose your Platform API Key in client-side code

Always use HTTPS

Verify webhook signatures

Store API keys securely

5. Error Handling
Show user-friendly error messages

Log all errors for debugging

Provide retry options

🆘 Support
Contact Information
Email: support@kupursa.store

Phone: +255 711 777 636

WhatsApp: +255 711 777 636

Merchant Dashboard
Access your dashboard to:

View your Platform API Key

See transaction history

Configure webhook URL

Manage your account